<?php


namespace App\Repositories;


use App\Models\OrderProduct;
use App\Models\Picking as Model;
use App\Models\PickingDetail;
use App\Models\PickingOrder;
use App\Traits\CodeTrait;
use App\Traits\Logs;
use Exception;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use LTools\Repositories\RepositoryAbstract;
use Throwable;

class Picking extends RepositoryAbstract
{
    use CodeTrait, Logs;

    /**
     * Picking constructor.
     * @param Model $model
     * @author luffyzhao@vip.126.com
     */
    public function __construct(Model $model)
    {
        $this->model = $model;
    }

    /**
     * @param array $attributes
     * @param int|null $perPage
     * @param array $columns
     * @param string $pageName
     * @param int|null $page
     * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
     * @author luffyzhao@vip.126.com
     */
    public function paginate(array $attributes, int $perPage = null, array $columns = ['*'], $pageName = 'page', int $page = null)
    {
        return $this->model->with(['user'])->where(
            $attributes
        )->paginate($perPage, $columns, $pageName, $page);
    }

    /**
     * @param Collection $collection
     * @throws Throwable
     * @author luffyzhao@vip.126.com
     */
    public function createPicking(Collection $collection)
    {
        if ($collection->count() === 0) {
            return;
        }
        $values = [];
        $values['type'] = $collection->first()['type'];
        $values['code'] = $this->unique(4, 'P' . date('Ymd'));
        $values['count'] = 0;

        /** @var Model $model */
        $model = parent::create($values);

        /** @var BatchInventory $batchInventory */
        $batchInventory = app(BatchInventory::class);
        /** @var \App\Models\OrderShipment $shipment */
        foreach ($collection as $shipment) {
            try {
                DB::beginTransaction();
                // 加锁
                $shipment = \App\Models\OrderShipment::query()
                    ->with(['order.products'])
                    ->where('id', '=', $shipment->getKey())
                    ->lockForUpdate()->first();

                if ($shipment->getAttribute('status') !== 0) {
                    throw new Exception("出货单状态不是待生成");
                }

                /** @var OrderProduct $product */
                foreach ($shipment->order->products as $product) {
                    try{
                        // 减批次库存
                        $batches = $batchInventory->productDecrement(
                            $product->getAttribute('product_id'),
                            $product->getAttribute('quantity'),
                            $product->getAttribute('attribute'),
                            $product->getAttribute('expire'),
                            $product->getAttribute('expiry')
                        );
                        // 写入下架单详情
                        foreach ($batches as $batch) {
                            $model->detail()->create(
                                array_merge($batch, ['order_id'=> $shipment->getAttribute('order_id')])
                            );
                        }
                    }catch (Exception $exception){
                        throw new Exception(sprintf($exception->getMessage(), $product->product->getAttribute('code')));
                    }
                }

                // 更新出货单状态
                $shipment->setAttribute('status', 1);
                $shipment->saveOrFail();
                // 添加到下架订单列表
                $model->order()->create($shipment->toArray());
                // 波次生成
                $this->recordLogs($shipment, "已生成波次");
                DB::commit();
            } catch (Exception | Throwable $exception) {
                DB::rollBack();
                $this->recordLogs($shipment, sprintf("仓单号[%s]生成波次失败:%s", $shipment->order->getAttribute('code'), $exception->getMessage()));
            }
        }
        // 没有成功下架订单时删除这个下架单
        $count = $model->order()->count();
        if ($count === 0) {
            $model->delete();
        }else{
            // 更新订单数
            $model->update([
                'count' => $count
            ]);
        }
        $this->recordLogs($model, "下架单生成!");
    }

    /**
     * @param array $search
     * @param $id
     * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
     * @author luffyzhao@vip.126.com
     */
    public function show(array $search, $id)
    {
        /** @var Model $model */
        $model = $this->find($id);
        return $model->detail()->where($search)->with(['order'])->paginate();
    }

    /**
     * @param $id
     * @param array $values
     * @return bool|\Illuminate\Database\Eloquent\Model
     * @throws Throwable
     * @author luffyzhao@vip.126.com
     */
    public function update($id, array $values)
    {
        /** @var Model $model */
        $model = $this->model->newQuery()->lockForUpdate()->findOrFail($id);
        if ($model->getAttribute('status') === 0) {
            $model->setAttribute('status', 1);
            $model->setAttribute('user_id', $values['user_id']);
            $model->saveOrFail();

            $this->recordLogs($model, "下架单已分配");
            return $model;
        }
        throw new Exception("下架单分配失败！");
    }

    /**
     * @param $id
     * @return Model
     * @throws Throwable
     * @author luffyzhao@vip.126.com
     */
    public function picking($id)
    {
        /** @var Model $model */
        $model = $this->model->newQuery()->lockForUpdate()->findOrFail($id);
        if ($model->getAttribute('status') === 1) {
            $model->setAttribute('status', 2);
            $model->saveOrFail();

            //
            $model->order->each(function (PickingOrder $order) {
                /** @var \App\Models\OrderShipment $shipment */
                $shipment = $order->shipment()->lockForUpdate()->first();
                if ($shipment->getAttribute('status') === 1) {
                    $shipment->setAttribute('status', 2);
                    $shipment->saveOrFail();

                    $this->recordLogs($shipment, "订单已下架");
                } else {
                    throw new Exception(sprintf("出货单[%s]不是待下架状态不能下架！", $shipment->order->getAttribute('code')));
                }
            });


            $this->recordLogs($model, "下架单已下架");
            return $model;
        }
        throw new Exception("下架单下架失败！");
    }

    /**
     * 按订单
     * @param $id
     * @return array
     * @author luffyzhao@vip.126.com
     */
    public function printForOrder($id)
    {
        return [
            'url' => Storage::url("picking.pdf")
        ];
    }


    /**
     * 按货位
     * @param $id
     * @return array
     * @author luffyzhao@vip.126.com
     */
    public function printForLocation($id)
    {
        return [
            'url' => Storage::url("picking.pdf")
        ];
    }

}
